---
--Bones
--Copyright (C) 2012 Bad_Command
--
--This library is free software; you can redistribute it and/or
--modify it under the terms of the GNU Lesser General Public
--License as published by the Free Software Foundation; either
--version 2.1 of the License, or (at your option) any later version.
--
--This program is distributed in the hope that it will be useful,
--but WITHOUT ANY WARRANTY; without even the implied warranty of
--MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
--GNU General Public License for more details.
--
--You should have received a copy of the GNU Lesser General Public
--License along with this library; if not, write to the Free Software
--Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
----

bones.replaceable_node_types = {
	"default:lava_source", 
	"default:lava_flowing", 
	"default:water_source", 
	"default:water_flowing", 
	"air"
}

bones.allow_inventory_take = function(pos, listname, index, stack, player)
	local meta = minetest.env:get_meta(pos)
	if not bones.privilege(meta, player) then
		minetest.log("action", player:get_player_name().." tentou acessar os Ossos pertencentes a '"..meta:get_string("owner").."' em ("..minetest.pos_to_string(pos)..").")
		return 0
	end
	return stack:get_count()
end

bones.on_inventory_take = function(pos, listname, index, stack, player)
	local fresh = meta:get_int("fresh") or 1
	if fresh > 0 then
		fresh = "fresh"
	else
		fresh = "old"
	end
	minetest.log("action", player:get_player_name().." pegou as 'Bones "..fresh.."' de '"..meta:get_string("owner").."' em ("..minetest.pos_to_string(pos)..").")
end

bones.privilege=function(meta, player)
	local name = player:get_player_name()
	local privs = minetest.get_player_privs(name)
	if not privs["interact"] then
		return false
	end
	local fresh = meta:get_int("fresh") or 0
	if fresh > 0 and name ~= meta:get_string("owner") and not privs["server"] then
		return false
	end
	return true
end

bones.action=function(pos, node, active_object_count, active_object_count_wider)
	local meta = minetest.env:get_meta(pos)
	local fresh = meta:get_int("fresh") or 0
	if fresh > 0 then
		local bonetime = meta:get_string("bonetime") or 0
		--if worldtime_get() - bonetime >  bones.age_after then
		local now = os.time() --Em milisegundos
		--print("now='"..now.."'")
		--print("bonetime='"..bonetime.."'")
		--print("now - bonetime >  bones.age_after :::: ["..(now - bonetime).."] > ["..bones.age_after.."]")
		local name = meta:get_string("owner") or ""
		local restante = bones.age_after - (now - bonetime)
		if restante<0 or restante>bones.age_after -- <=Caso de erro nas versoes de bones anteriores
			or now - bonetime >  bones.age_after -- <=Caso a bone tenha envelhecido normalmente
		then
			meta:set_string("infotext", "Osso Velhos de '"..name .. "' (Disponivel).")
			meta:set_int("fresh", -1)
		else
			meta:set_string("infotext", "Osso Novo de '"..name .. "' (Protegido por "..restante.." segundos).")
		end
	end
end	

bones.create = function(player, pos) 
	local name = player:get_player_name()
	minetest.env:set_node(pos, {name="bones:bones", param1=0, param2=0})
	local meta = minetest.env:get_meta(pos)
	meta:set_string("formspec",
			--"invsize[8,9;]".. -- <---está deprecado!!!!
			"size[8,9]"..
			"list[current_name;main;0,0;8,4;]"..
			"list[current_player;main;0,5;8,4;]")
	meta:set_string("infotext", "Osso Novo de '"..name .. "' (Protegido por "..bones.age_after.." segundos).")
	meta:set_string("owner", name)
	--meta:set_float("bonetime", worldtime_get())
	local now = os.time() --Em milisegundos
	meta:set_string("bonetime", now)
	--print("bones.create("..name..", "..dump(pos)..") >>>>>>>>>>>>>> bonetime='"..now.."'")
	meta:set_int("fresh", 1)

	-- test to see if node was created
	local node = minetest.env:get_node_or_nil(pos)
	if node == nil or node.name ~= "bones:bones" then
		minetest.log("error", 'Bones: Falha ao criar bloco de ossos para '..name.."'.")
		return false
	end

	local bones_inv = meta:get_inventory()
	bones_inv:set_size("main", 8*4)
	local player_inv = player:get_inventory()
	if ( player_inv == nil ) then
		minetest.log("error", "Bones: Impossivel obter inventario de '".. name .. "'.")
		return false
	end
	

	for i=1,32 do
		local stack = player_inv:get_stack("main", i)
		if stack ~= nil and not stack:is_empty() then
			bones_inv:set_stack("main", i, stack:to_table())
			player_inv:set_stack("main", i, nil)
		end
	end
	for i=1,9 do
		local stack = player_inv:get_stack("craft", i)
		if stack ~= nil and not stack:is_empty() then
			local leftover = bones_inv:add_item("main", stack)
			if leftover ~= nil and not leftover:is_empty() then
				minetest.env:add_item({
					x=pos.x, 
					y=pos.y + 1.1, 
					z=pos.z}, leftover)
			end
			player_inv:set_stack("craft", i, nil)			
		end
	end
	return true
end

bones.settle_type = function(nodename) 
	for i=1,#bones.replaceable_node_types do
		if nodename == bones.replaceable_node_types[i] then
			return true
		end
	end
	return false
end

bones.on_punch = function(pos, node, player)
	if node == nil or node.name ~= "bones:bones" then
		return
	end
	
	local meta = minetest.env:get_meta(pos)

	local fresh = meta:get_int("fresh") or 0
	if fresh == 0  then
		return
	end

	local name = player:get_player_name()
	if name ~= meta:get_string("owner") then
		return
	end

	local meta = minetest.env:get_meta(pos)
	local bones_inv = meta:get_inventory()
	if ( bones_inv == nil ) then
		return
	end
	
	local player_inv = player:get_inventory()
	if ( player_inv == nil ) then
		minetest.log("error", "Bones: Impossivel obter inventario de '".. name .. "'.")
		return
	end

	for i=1,32 do
		local stack = bones_inv:get_stack("main", i) --pega uma das 32 pilha de itens da bone
		if stack ~= nil and not stack:is_empty() then --verifica se a pila pegada esta vazia
			local leftover = player_inv:add_item("main", stack) --adiciona item a uma pilha vazia do inventario do usuario. (se nao houver espaco, retornara a pilha como resultado
			bones_inv:set_stack("main", i, nil) --apaga a pilha de numero N do osso
			if leftover ~= nil and not leftover:is_empty() then -- verifica se a pilha nao retornou por motivo de inventario de usuarios esta cheio.
				bones_inv:set_stack("main", i, leftover) --Se o inventario do usuario estiver cheio. E devolvido a pilha de numero N ao osso
			else
				bones_inv:set_stack("main", i, nil) -- confirma que a pilha de numero N do osso foi apagada.
			end
		end
	end
	--minetest.log("action", name.." unloaded his fresh bones at "..minetest.pos_to_string(pos))
	minetest.log("action", name.." descarregado seus ossos novos em ("..minetest.pos_to_string(pos)..").")
end


bones.settle_bones = function(pos) 
	local nextpos = pos; 
	local node

	-- find ground beneath player
	repeat
		pos = nextpos
		nextpos = {x=pos.x, y=pos.y-1, z=pos.z}
		node = minetest.env:get_node_or_nil(nextpos)
	until node == nil or not bones.settle_type(node.name) 

	node = minetest.env:get_node_or_nil(pos)

	-- if the player is inside rock or something
	if node == nil or not bones.settle_type(node.name) then
		-- find nearby empty node
		pos = minetest.env:find_node_near(pos, 3, bones.replaceable_node_types)
	end

	-- if nothing nearby is empty
	if pos == nil then
		return nil
	end

	return pos;--{x=math.floor(pos.x*10)/10, y=math.floor(pos.y*10)/10, z=math.floor(pos.z*10)/10}
end

bones.pos_to_string = function(pos) 
	return math.floor(pos.x + 0.5) .. "," .. math.floor(pos.y+0.5) .. "," .. math.floor(pos.z+0.5)
end

bones.on_dieplayer = function(player) 
	if player == nil or not player:is_player() then
		minetest.log("error", 'Jogador desconhecido morreu.')
		return
	end

	local name = player:get_player_name()
	local privs = minetest.get_player_privs(name)
	local inv = player:get_inventory()

	if not privs["interact"] or (inv:is_empty("main") and inv:is_empty("craft")) then
		return
	end
	
	local playerpos = player:getpos()
	playerpos = { 
		x=math.floor(playerpos.x+0.5),
		y=math.floor(playerpos.y+0.5),
		z=math.floor(playerpos.z+0.5)
	}
	local bonepos = bones.settle_bones(playerpos);
	if bonepos == nil then
		--minetest.log("action", player:get_player_name().." dies at "..minetest.pos_to_string(playerpos)..' without dropping gear.')
		minetest.log("action", player:get_player_name().." morreu em ("..minetest.pos_to_string(playerpos)..") sem deixar cair seus inventario.")
		--minetest.chat_send_player(name, 'Bones:  There was no room to drop your bones.  You get to keep your gear.')
		minetest.chat_send_player(name, "Bones: Nao havia lugar para deixar cair seus ossos. Voce tera que manter o seu equipamento.")
		return
	else
		if bones.create(player, bonepos) then
			--minetest.log("action", player:get_player_name().." dies at "..minetest.pos_to_string(playerpos)..', gear dropped at '..minetest.pos_to_string(bonepos))
			minetest.log("action", player:get_player_name().." morreu em ("..minetest.pos_to_string(playerpos)..") e seu inventario caiu em ("..minetest.pos_to_string(bonepos).."'.")
			minetest.chat_send_player(name, 
				"Bones:  Seus ossos foram deixados em ("..bones.pos_to_string(bonepos)..").  "..
				"Va ate la para encontrar o seu inventario. Os seus ossos ficarao protegido por "..(math.floor(bones.age_after/360+0.5)/10)..' horas.'
			)
		else
			minetest.chat_send_player(name, "Seu dia de Sorte! Voce comeca a renascer com seus ossos.")			
		end
	end
end
